import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from typing import Dict, Any, List, Optional
from datetime import datetime, timedelta
from dataclasses import dataclass
from enum import Enum
import json
import aiohttp

from app.core.payment_logger import payment_logger, PaymentLogLevel, PaymentEventType
from app.core.config import settings

class AlertLevel(Enum):
    """告警级别"""
    LOW = "low"
    MEDIUM = "medium"
    HIGH = "high"
    CRITICAL = "critical"

class AlertType(Enum):
    """告警类型"""
    PAYMENT_FAILURE_RATE = "payment_failure_rate"
    SIGNATURE_VALIDATION_FAILURE = "signature_validation_failure"
    SERVICE_UNAVAILABLE = "service_unavailable"
    TIMEOUT_ORDERS = "timeout_orders"
    CONFIGURATION_ERROR = "configuration_error"
    CALLBACK_PROCESSING_ERROR = "callback_processing_error"

@dataclass
class Alert:
    """告警信息"""
    alert_type: AlertType
    level: AlertLevel
    message: str
    details: Dict[str, Any]
    timestamp: datetime
    resolved: bool = False

class PaymentAlertManager:
    """支付告警管理器"""
    
    def __init__(self):
        self.alert_thresholds = {
            AlertType.PAYMENT_FAILURE_RATE: 0.1,  # 10%失败率触发告警
            AlertType.SIGNATURE_VALIDATION_FAILURE: 5,  # 5次签名验证失败
            AlertType.TIMEOUT_ORDERS: 10,  # 10个超时订单
        }
        self.alert_history: List[Alert] = []
        self.notification_channels = self._setup_notification_channels()
    
    def _setup_notification_channels(self) -> Dict[str, Any]:
        """设置通知渠道"""
        channels = {}
        
        # 邮件通知配置
        if hasattr(settings, 'SMTP_SERVER'):
            channels['email'] = {
                'enabled': True,
                'smtp_server': getattr(settings, 'SMTP_SERVER', ''),
                'smtp_port': getattr(settings, 'SMTP_PORT', 587),
                'smtp_user': getattr(settings, 'SMTP_USER', ''),
                'smtp_password': getattr(settings, 'SMTP_PASSWORD', ''),
                'recipients': getattr(settings, 'ALERT_EMAIL_RECIPIENTS', [])
            }
        
        # 企业微信通知配置
        if hasattr(settings, 'WECHAT_WORK_WEBHOOK'):
            channels['wechat_work'] = {
                'enabled': True,
                'webhook_url': getattr(settings, 'WECHAT_WORK_WEBHOOK', '')
            }
        
        # 钉钉通知配置
        if hasattr(settings, 'DINGTALK_WEBHOOK'):
            channels['dingtalk'] = {
                'enabled': True,
                'webhook_url': getattr(settings, 'DINGTALK_WEBHOOK', ''),
                'secret': getattr(settings, 'DINGTALK_SECRET', '')
            }
        
        return channels
    
    async def trigger_alert(
        self,
        alert_type: AlertType,
        level: AlertLevel,
        message: str,
        details: Dict[str, Any],
        provider: Optional[str] = None,
        order_id: Optional[str] = None
    ):
        """触发告警"""
        alert = Alert(
            alert_type=alert_type,
            level=level,
            message=message,
            details=details,
            timestamp=datetime.now()
        )
        
        # 记录告警日志
        payment_logger.log_payment_event(
            PaymentEventType.SERVICE_ERROR,
            PaymentLogLevel.CRITICAL if level == AlertLevel.CRITICAL else PaymentLogLevel.ERROR,
            f"支付告警触发: {message}",
            order_id=order_id,
            provider=provider,
            extra_data={
                "alert_type": alert_type.value,
                "alert_level": level.value,
                "alert_details": details
            }
        )
        
        self.alert_history.append(alert)
        
        # 发送通知
        await self._send_notifications(alert, provider, order_id)
        
        return alert
    
    async def _send_notifications(self, alert: Alert, provider: Optional[str], order_id: Optional[str]):
        """发送告警通知"""
        for channel_name, channel_config in self.notification_channels.items():
            if not channel_config.get('enabled', False):
                continue
                
            try:
                if channel_name == 'email':
                    await self._send_email_notification(alert, channel_config, provider, order_id)
                elif channel_name == 'wechat_work':
                    await self._send_wechat_work_notification(alert, channel_config, provider, order_id)
                elif channel_name == 'dingtalk':
                    await self._send_dingtalk_notification(alert, channel_config, provider, order_id)
            except Exception as e:
                payment_logger.log_service_error(
                    "alert_manager",
                    e,
                    order_id,
                    {"channel": channel_name, "alert_type": alert.alert_type.value}
                )
    
    async def _send_email_notification(
        self, 
        alert: Alert, 
        config: Dict[str, Any], 
        provider: Optional[str], 
        order_id: Optional[str]
    ):
        """发送邮件通知"""
        if not config.get('recipients'):
            return
            
        try:
            msg = MIMEMultipart()
            msg['From'] = config['smtp_user']
            msg['To'] = ', '.join(config['recipients'])
            msg['Subject'] = f"[ThrushAI] 支付系统告警 - {alert.level.value.upper()}"
            
            # 构建邮件内容
            body = f"""
支付系统告警

告警级别: {alert.level.value.upper()}
告警类型: {alert.alert_type.value}
告警时间: {alert.timestamp.strftime('%Y-%m-%d %H:%M:%S')}
支付提供商: {provider or '未知'}
订单ID: {order_id or '未知'}

告警信息:
{alert.message}

详细信息:
{json.dumps(alert.details, indent=2, ensure_ascii=False)}

请及时处理此告警。
            """
            
            msg.attach(MIMEText(body, 'plain', 'utf-8'))
            
            # 发送邮件
            server = smtplib.SMTP(config['smtp_server'], config['smtp_port'])
            server.starttls()
            server.login(config['smtp_user'], config['smtp_password'])
            server.sendmail(config['smtp_user'], config['recipients'], msg.as_string())
            server.quit()
            
        except Exception as e:
            raise Exception(f"邮件发送失败: {str(e)}")
    
    async def _send_wechat_work_notification(
        self, 
        alert: Alert, 
        config: Dict[str, Any], 
        provider: Optional[str], 
        order_id: Optional[str]
    ):
        """发送企业微信通知"""
        webhook_url = config.get('webhook_url')
        if not webhook_url:
            return
            
        color = {
            AlertLevel.LOW: 'info',
            AlertLevel.MEDIUM: 'warning',
            AlertLevel.HIGH: 'warning',
            AlertLevel.CRITICAL: 'error'
        }.get(alert.level, 'info')
        
        data = {
            "msgtype": "markdown",
            "markdown": {
                "content": f"""# 支付系统告警
                
> **告警级别**: <font color="{color}">{alert.level.value.upper()}</font>
> **告警类型**: {alert.alert_type.value}
> **告警时间**: {alert.timestamp.strftime('%Y-%m-%d %H:%M:%S')}
> **支付提供商**: {provider or '未知'}
> **订单ID**: {order_id or '未知'}

**告警信息**: {alert.message}

**详细信息**:
```json
{json.dumps(alert.details, indent=2, ensure_ascii=False)}
```

请及时处理此告警。
                """
            }
        }
        
        async with aiohttp.ClientSession() as session:
            async with session.post(webhook_url, json=data) as response:
                if response.status != 200:
                    raise Exception(f"企业微信通知发送失败，状态码: {response.status}")
    
    async def _send_dingtalk_notification(
        self, 
        alert: Alert, 
        config: Dict[str, Any], 
        provider: Optional[str], 
        order_id: Optional[str]
    ):
        """发送钉钉通知"""
        webhook_url = config.get('webhook_url')
        if not webhook_url:
            return
            
        data = {
            "msgtype": "markdown",
            "markdown": {
                "title": "支付系统告警",
                "text": f"""# 支付系统告警
                
**告警级别**: {alert.level.value.upper()}  
**告警类型**: {alert.alert_type.value}  
**告警时间**: {alert.timestamp.strftime('%Y-%m-%d %H:%M:%S')}  
**支付提供商**: {provider or '未知'}  
**订单ID**: {order_id or '未知'}  

**告警信息**: {alert.message}

请及时处理此告警。
                """
            }
        }
        
        async with aiohttp.ClientSession() as session:
            async with session.post(webhook_url, json=data) as response:
                if response.status != 200:
                    raise Exception(f"钉钉通知发送失败，状态码: {response.status}")
    
    def check_failure_rate_threshold(self, provider: str, success_count: int, failure_count: int):
        """检查失败率阈值"""
        total_count = success_count + failure_count
        if total_count == 0:
            return
            
        failure_rate = failure_count / total_count
        threshold = self.alert_thresholds[AlertType.PAYMENT_FAILURE_RATE]
        
        if failure_rate > threshold:
            return self.trigger_alert(
                AlertType.PAYMENT_FAILURE_RATE,
                AlertLevel.HIGH if failure_rate > threshold * 2 else AlertLevel.MEDIUM,
                f"支付失败率过高: {failure_rate:.2%}",
                {
                    "provider": provider,
                    "success_count": success_count,
                    "failure_count": failure_count,
                    "failure_rate": failure_rate,
                    "threshold": threshold
                },
                provider=provider
            )
    
    def get_alert_statistics(self, hours: int = 24) -> Dict[str, Any]:
        """获取告警统计信息"""
        cutoff_time = datetime.now() - timedelta(hours=hours)
        recent_alerts = [alert for alert in self.alert_history if alert.timestamp > cutoff_time]
        
        stats = {
            "total_alerts": len(recent_alerts),
            "by_level": {},
            "by_type": {},
            "resolved_count": sum(1 for alert in recent_alerts if alert.resolved),
            "latest_alerts": [
                {
                    "type": alert.alert_type.value,
                    "level": alert.level.value,
                    "message": alert.message,
                    "timestamp": alert.timestamp.isoformat(),
                    "resolved": alert.resolved
                }
                for alert in sorted(recent_alerts, key=lambda x: x.timestamp, reverse=True)[:10]
            ]
        }
        
        # 按级别统计
        for alert in recent_alerts:
            level = alert.level.value
            stats["by_level"][level] = stats["by_level"].get(level, 0) + 1
        
        # 按类型统计
        for alert in recent_alerts:
            alert_type = alert.alert_type.value
            stats["by_type"][alert_type] = stats["by_type"].get(alert_type, 0) + 1
        
        return stats

# 全局告警管理器实例
payment_alert_manager = PaymentAlertManager()